﻿using System.Collections.Generic;
using Actors.ActorComponents;
using Actors.Actions;
using UnityEngine;

namespace Actors
{
    public class ActorInitParams
    {
        
    }
    
    /// <summary>
    /// Actor 逻辑类
    /// </summary>
    public abstract class Actor : IActionExecutor
    {
        static long s_UIDCounter = 0;
        
        #region Members
        private long m_UID = 0;
        public long UID => m_UID;
        
        protected readonly List<ActorComponent> Components;

        protected ActorVisual m_ActorVisual;
        public ActorVisual ActorVisual => m_ActorVisual;

        private Transform m_Transform;
        public Transform transform
        {
            get
            {
                if (m_Transform == null)
                {
                    m_Transform = m_ActorVisual?.gameObject.transform;
                }

                return m_Transform;
            }
        }
        
        private GameObject m_GameObject;
        public GameObject gameObject
        {
            get
            {
                if (m_GameObject == null)
                {
                    m_GameObject = m_ActorVisual?.gameObject;
                }

                return m_GameObject;
            }
        }


        public bool EnableUpdate { get; protected set; } = false;
        public bool EnableFixedUpdate { get; protected set; } = false;
        #endregion

        public Actor()
        {
            m_UID = ++s_UIDCounter;
            Components = new List<ActorComponent>();
        }
        
        public virtual void Update()
        {
            UpdateActorComponents();
        }

        public virtual void FixedUpdate()
        {
        }

        #region Initialization

        public virtual void Initialize(ActorInitParams initParams)
        {
            InitVisual();
            InitComponents();
            InitCustom();
        }

        protected virtual void InitVisual()
        {
            m_ActorVisual = new ActorVisual(this);
        }
        
        protected virtual void InitComponents()
        {

        }

        protected virtual void InitCustom()
        {
            
        }

        #endregion
        

        #region Components

        public void AddActorComponent(ActorComponent component)
        {
            Components.Add(component);
        }
        
        public T AddActorComponent<T>() where T : ActorComponent, new()
        {
            var component = new T();
            AddActorComponent(component);
            return component;
        }
        
        public void RemoveActorComponent(ActorComponent component)
        {
            Components.Remove(component);
        }
        
        public T GetActorComponent<T>() where T : ActorComponent
        {
            foreach (var component in Components)
            {
                if (component is T actorComponent)
                {
                    return actorComponent;
                }
            }

            return null;
        }
        
        public T RequireActorComponent<T>() where T : ActorComponent, new()
        {
            var component = GetActorComponent<T>() ?? AddActorComponent<T>();

            return component;
        }
        
        private void UpdateActorComponents()
        {
            foreach (var component in Components)
            {
                if (component != null && component.Enabled)
                {
                    component.Update();
                }
            }
        }

        #endregion


        #region Action        
        public abstract bool CanExecute(Action action);
        public abstract bool ExecuteAction(Action action);
        #endregion
    }
}